﻿#region

using System;

#endregion

namespace SharpObservation
{
    /// <summary>
    /// Base class for implementing a disposable event-based class, for types which expose events.
    /// </summary>
    /// <remarks>
    /// Derive from this class, then implement events as follows:
    /// <code>
    /// private readonly static EventKey&lt;PropertyChangingEventHandler&gt; PropertyChangingEventKey = new EventKey&lt;PropertyChangingEventHandler&gt;();
    /// 
    /// public event PropertyChangingEventHandler PropertyChanging
    /// {
    ///     add { AddHandler(PropertyChangingEventKey, value); }
    ///     remove { RemoveHandler(PropertyChangingEventKey, value); }
    /// }
    /// 
    /// protected void RaiseName()
    /// {
    ///     RaiseEvent(PropertyChangingEventKey, raiseEvent =&gt; raiseEvent(this, new PropertyChangingEventArgs("Name")));
    /// }
    /// </code>
    /// A snippet is available (if installed from Snippets.vsi) to create events, just type: "soevt [tab][tab]"
    /// </remarks>
    public abstract class DisposableEventsObject
          : EventsObject
          , IIsDisposed
          , IDisposedEvent
    {
        #region IDisposedEvent Members

        /// <summary>
        /// Event Key for managing the Disposing event
        /// </summary>
        internal readonly static EventKey<EventHandler> DisposingEventKey = new EventKey<EventHandler>();
        
        /// <summary>
        ///   Provides notification that this instance is being disposed.
        /// </summary>
        public event EventHandler Disposed
        {
            add { AddHandler(DisposingEventKey, value); }
            remove { RemoveHandler(DisposingEventKey, value); }
        }

        #endregion

        /// <summary>
        /// Handles disposal
        /// </summary>
        /// <param name = "disposing">True if Dispose was called. False if finalizing</param>
        protected virtual void Dispose(bool disposing)
        {
            // Raise the Disposing event
            RaiseEvent(DisposingEventKey, raiseEvent => raiseEvent(this, EventArgs.Empty));
        }


        private bool isDisposed;
        private Action throwIfDisposed = () => { };

        /// <summary>
        ///   Gets whether the factory instance has been disposed.
        /// </summary>
        public bool IsDisposed { get { return isDisposed; } }

        /// <summary>
        ///   Checks whether the factory instance has been disposed, and throws an ObjectDisposedException if it has
        /// </summary>
        /// <exception cref = "ObjectDisposedException">Thrown if instance has been disposed</exception>
        protected Action ThrowIfDisposed { get { return throwIfDisposed; } }


        /// <summary>
        ///   Disposes the factory instance
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")]
        public void Dispose()
        {
            DisposeHelper.DisposeOf(this, true);
        }

        ///// <summary>
        /////   Finalizes the factory instance. Should never be called.
        ///// </summary>
        //[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")]
        //~DisposableObject()
        //{
        //    DisposeHelper.DisposeOf(this, false);
        //}
    }
}